還記得上一篇我們寫到一半的 Modules 介紹嗎?今天要來把剩下的部分給補完。
那麼就開始吧!
還記得 Rust 的物件預設都是 private 的這件事情嗎?這是上一次的範例所遇到的錯誤
$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0603]: module `hosting` is private
--> src/lib.rs:9:28
|
9 | crate::front_of_house::hosting::add_to_waitlist();
| ^^^^^^^
error[E0603]: module `hosting` is private
--> src/lib.rs:12:21
|
12 | front_of_house::hosting::add_to_waitlist();
| ^^^^^^^
因此我們就來改改看原本那支程式讓 hosting
變成 public 的試試看。
mod front_of_house {
pub mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
結果還是錯的,
$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0603]: function `add_to_waitlist` is private
--> src/lib.rs:9:37
|
9 | crate::front_of_house::hosting::add_to_waitlist();
| ^^^^^^^^^^^^^^^
error[E0603]: function `add_to_waitlist` is private
--> src/lib.rs:12:30
|
12 | front_of_house::hosting::add_to_waitlist();
| ^^^^^^^^^^^^^^^
原因是我們只有 public hosting 這個 module 但是裡面的內容仍然還是 private 的,若是我們想要取用到裡面的函式我們同樣要把他 public 出來。
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
這樣就會 work 了!
super
這邊的 super 在 path 的相對路徑裡面就等同於檔案系統的 ..
也就是上一層的意思,我們直接看一個範例吧。
fn serve_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order();
}
fn cook_order() {}
}
在 back_of_house
module 裡面的程式可以透過 super 先到上一層這邊也就是我們的 crate root 然後再拿到 serve_order
這支程式。
我們用檔案路徑來舉例應該會更清楚,
假如這是我當前的目錄 crate/back_of_house/
然後我 cd ..
到上一層就變成 crate/
然後我再 cd serve_order
就變成 crate/serve_order/
。
struct 和 enum(還沒寫到之後寫一下),也可以使用 pub
不過要注意的是 struct 的欄位並不會跟著一起 public 出去,舉例來說下面這支程式的 Breakfast
只有 toast
的欄位有被 public 出去而 seasonal_fruit
仍然是 private 的。
mod back_of_house {
pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}
impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
}
pub fn eat_at_restaurant() {
// Order a breakfast in the summer with Rye toast
let mut meal = back_of_house::Breakfast::summer("Rye");
// Change our mind about what bread we'd like
meal.toast = String::from("Wheat");
println!("I'd like {} toast please", meal.toast);
// The next line won't compile if we uncomment it; we're not allowed
// to see or modify the seasonal fruit that comes with the meal
// meal.seasonal_fruit = String::from("blueberries");
}
上面這個例子我們可以看到 meal.toast
因為是 public 的所以可以修改但是 meal.seasonal_fruit
是 private 的所以編譯會報錯。
另外一個重點是我們必須在 back_of_house
的 module 裡面定義一支程式(這邊是 summer 這支程式)讓我們可以使用 Breakfast
,否則因為 Breakfast
的 seasonal_fruit
是 private 的欄位我們無法在外面宣告他,只能仰賴 summer
做這件事情。
反之若是我們 pub
enum
則會全部都變成 public 的我們只需要宣告一次即可例如,
mod back_of_house {
pub enum Appetizer {
Soup,
Salad,
}
}
pub fn eat_at_restaurant() {
let order1 = back_of_house::Appetizer::Soup;
let order2 = back_of_house::Appetizer::Salad;
// enum 不用替他的欄位宣告 pub 我想應該跟實作方式有關,但我還不想去翻 source code XD
}
上面的例子可以看到我把 Appetizer
pub
之後就可以拿到他裡面的 Soup
和 Salad
而不用另外宣告。
今天把 pub 的概念都學完了不過其實我也只是縮短了官網的內容然後寫下來 XD,希望對已經不是程式菜鳥的各位有幫助,因為我有時候覺得官網太新手向廢話字有點多。
那麼下一篇的主題就是 use
,雖然我們已經用得蠻多了不過還是可以再來順一次內容看看有沒有漏掉的。
以上是今天的內容鐵人賽雖然快結束了但是我會把繼續這個系列完成的,那麼我們明天見!
ch07-03-paths-for-referring-to-an-item-in-the-module-tree